/*************************************************************************
 * @file: hedmodel.h
 * @date: 01/04/2012
 * TOPOL v1_0 - (c)copyright 2012 TEC/UFF
 *************************************************************************
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 ************************************************************************/

#ifndef _HEDMODEL	
#define _HEDMODEL

// includes
//----------
#include "entity/ipoint.h"
#include <vector>
using namespace std;

// forward declarations
//----------------------
class Solid;
class Face;
class HalfEdge;
class Edge;
class Vertex;


/*!
 * CLASS
 * HEDModel
 * 
 * This class is responsible for management of the topological entities
 * in the Data Structure, on how to store, remove and manipulate them.
 * It basically keeps a pointer to an element of a lists of Solids, since
 * that from the solids it is possible to access any other entity.
 * 
 * @author Andre Pereira (andremaues@id.uff.br)
 * @version 1.0.0
 * @see Solid
 * @see Face
 * @see HalfEdge
 * @see Edge
 * @see Vertex
 */
class HEDModel
{

public:

  ////////////////////////////////////////////////
  ///  Constructor and Destructor Declaration  ///
  ////////////////////////////////////////////////

  /**
   * @brief Constructs the object that represents the model of the Data Structure
   */
  HEDModel();

  ////////////////////////////////////
  ///  PUBLIC Methods Declaration  ///
  ////////////////////////////////////

  /**
   * @brief Gets the first solid in the list of solids
   * @return Solid* is the first solid of the list
   */
	Solid* getFirsts();

  /**
   * @brief Gets the solid from the model that has the given identity _sn
   * @param _sn is the identity of the desired solid
   * @return Solid* is the solid with identity _sn
   */
	Solid* getSolid( int _sn );

  /**
   * @brief Gets the face of the solid _s, that has the given identity _fn
   * @param _sn is the identity of the solid that contains the face
   * @param _fn is the identity of the desired face
   * @return Face* is the face with identity _fn
   */
	Face* fface( Solid* _s, int _fn );

  /**
   * @brief Gets the half-edge that belong to face _f and that is between
   *        the vertexes _vn1 and _vn2
   * @param _f is the face that owns the desired half-edge
   * @param _vn1 is the first vertex of the half-edge
   * @param _vn2 is the second vertex of the half-edge
   * @return HalfEdge* is the half-edge between _vn1 and _vn2
   */
	HalfEdge* fhe( Face* _f, int _vn1, int _vn2 );

  /**
   * @brief Gets the vertex that has the identity _vn
   * @param _vn is the identity of the desired vertex
   * @return Vertex* is the pointer to the vertex with id _vn
   */
  Vertex* getVertex( int _vn );

  /**
   * @brief Gets the face whose coordinates (x,y,z) lie in, with a given tolerance
   * @param _x is the first coordinate of the point on the face
   * @param _y is the second coordinate of the point on the face
   * @param _z is the third coordinate of the point on the face
   * @param _tol is the tolerance
   * @return Face* is the desired face (it is NULL in case the conditions are not satisfied)
   */
  Face* getFace( double _x, double _y, double _z, double _tol );

  /**
   * @brief Gets the edge whose coordinates (x,y,z) lie in, with a given tolerance
   * @param _x is the first coordinate of the point on the edge
   * @param _y is the second coordinate of the point on the edge
   * @param _z is the third coordinate of the point on the edge
   * @param _tol is the tolerance
   * @return Edge* is the desired edge (it is NULL in case the conditions are not satisfied)
   */
  Edge* getEdge( double _x, double _y, double _z, double _tol );

  /**
   * @brief Gets the vertex closest to the point with coordinates (x,y,z), with a given tolerance
   * @param _x is the first coordinate of the reference point
   * @param _y is the second coordinate of the reference point
   * @param _z is the third coordinate of the reference point
   * @param _tol is the tolerance
   * @return Vertex* is the desired vertex (it is NULL in case the conditions are not satisfied)
   */
  Vertex* getVertex( double _x, double _y, double _z, double _tol );

  /**
   * @brief Gets the quantity of faces in the model
   * @return size_t is the number of faces
   */
  size_t getNumberOfFaces();

  /**
   * @brief Gets the quantity of vertexes in the model
   * @return size_t is the number of vertexes
   */
  size_t getNumberOfVertexes();

  /**
   * @brief Gets all the faces of the model
   * @return vector<Face*> is a container with all the faces
   */
  vector<Face*> getFaces();

  /**
   * @brief Gets all the edges of the model
   * @return vector<Edge*> is a container with all the edges
   */
  vector<Edge*> getEdges();

  /**
   * @brief Gets all the vertexes of the model
   * @return vector<Vertex*> is a container with all the vertexes
   */
  vector<Vertex*> getVertexes();

  /**
   * @brief Gets the half-edge that is most on the left of the segment
   *        between the given vertex _v and the coordinates (x,y,z)
   * @param _v is the vertex that the desired half-edge starts
   * @param _x is the first coordinate of the reference point
   * @param _y is the second coordinate of the reference point
   * @param _z is the third coordinate of the reference point
   * @return HalfEdge* is the desired half-edge
   */
  HalfEdge* getHalfEdge( Vertex* _v, double _x, double _y, double _z );

  /**
   * @brief Sets the first solid of the model
   * @param _firsts is the first solid of the model
   */
  void setFirsts( Solid* _firsts );

  /**
   * @brief Constructs a triangulation/tessellation for a non-convex hull given by
   *        a set of points [SKIENA & REVILLA, 2002. Programming Challenges, p.319]
   * @param _p is the set of points of the non-convex hull
   * @param _t is the triangulation of the region
   */
  void triagulate( vector<IPoint>& _p, vector<vector<int> >& _t );


  Edge* getEdge( int _v1, int _v2 );


private:

  /////////////////////////////////////
  ///  PRIVATE Methods Declaration  ///
  /////////////////////////////////////

  // creates a ear for the hull
  bool ear_Q( int _i, int _j, int _k, vector<IPoint*>& _p );
  // verifies if the point _p is inside the triangle _t
  bool point_in_triangle( IPoint* _p, vector<IPoint*>& _t );
  // verifies if the order of the triangle connectivity
  bool cw( IPoint* _a, IPoint* _b, IPoint* _c );
  // computes the area of a triangle keeping the sign of orientation
  double signed_triangle_area( IPoint* _a, IPoint* _b, IPoint* _c );

  ////////////////////////////////
  ///  Attributes Declaration  ///
  ////////////////////////////////

  /** @brief Is the first element of the list of solids */
	Solid* m_firsts;

};

#endif
